﻿/////////////////////////////////////////////
/// Author:     Anders K. Jacobsen
/// E-Mail:     anders@pings.dk
/// Date:       24. Mar 2008
/// /////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint;
using AKJ.Sharepoint.Branding.Config;
using AKJ.Sharepoint.Branding.BrandingInterceptor;
using AKJ.Sharepoint.Branding.Code;
using System.IO;

namespace AKJ.Sharepoint.Branding.HTTPModules
{
    /// <summary>
    /// 
    /// </summary>
    public class SharepointBrandingModule : IHttpModule
    {
        List<string> useUnsafePages = new List<string>();
        
        public SharepointBrandingModule()
        {
            useUnsafePages.AddRange(new string[] { "newsbweb.aspx", "checkin.aspx" });
        }
                
        public void Dispose()
        { }

        public void Init(HttpApplication context)
        {
            // Hook into preRequestHandler
            context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);            
        }
                        
        /// <summary>
        /// In the PreRequestHandlerExecute we change the master page for PublishingPages.
        /// For "normal" WSS 3.0 pags we let the PreInit Handler do the job.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void context_PreRequestHandlerExecute(object sender, EventArgs e)
        {
            if (HttpContext.Current == null)
                return;

            // Get an instance of the Page
            Page page = HttpContext.Current.CurrentHandler as Page;
            if (page == null)  return;

            // Get an instance of the HttpApplicaiton (so we can get the Request)
            HttpApplication currentApp = sender as HttpApplication;
            if (currentApp == null) return;

            // Now get the Request
            HttpRequest request = currentApp.Context.Request;

            // A few pages needs the AllowUnsafeUpdate set to true.
            AdjustUnsafeUpdateRequirement();

            // Build the branding index using available interceptors
            RebuildRebrandingIndex(page, request);

            if (page is PublishingLayoutPage || page is TemplateRedirectionPage)
            {
                // Now perform the 
                ProcessBrandings(page);
            }
            else if (page != null)
            {
                page.PreInit += new EventHandler(page_PreInit);
            }
        }                     
        
        /// <summary>
        /// First event where the Request instance is initialized
        /// (and before the Control structure is build so MasterPage
        /// can still be changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void page_PreInit(object sender, EventArgs e)
        {
           Page page = sender as Page;

             if (page == null)
                 return;
                       
            // Process the brandings
            ProcessBrandings(page);
        }        

        /// <summary>
        /// Enables AllowUnsafeUpdates in the current SPWeb object if a given page reqires this
        /// </summary>
        private void AdjustUnsafeUpdateRequirement()
        {
            string webpagename = Path.GetFileName(HttpContext.Current.Request.FilePath.ToLower());

            if (this.useUnsafePages.Contains(webpagename))
                SPContext.Current.Web.AllowUnsafeUpdates = !SPContext.Current.Web.AllowUnsafeUpdates;
        }

        /// <summary>
        /// Rebuild the Branding Index
        /// </summary>
        /// <param name="page"></param>
        private void RebuildRebrandingIndex(Page page, HttpRequest request)
        {
            BrandingManager.ClearBrandingCache();

            SortedDictionary<int, IBrandingInterceptor> inspectors = GetBrandingInterceptors();

            foreach (int key in inspectors.Keys)
            {
                IBrandingInterceptor inspector = inspectors[key];
                inspector.InterceptRequest(page,request);
            }
        }

        /// <summary>
        /// Parse request via branding modules
        /// </summary>
        /// <param name="page"></param>
        private void ProcessBrandings(Page page)
        {
            BrandingPair master = BrandingManager.GetCurrentBrandingElement(BrandingElementType.AKJ_Sharepoint_Master);
            BrandingPair css = BrandingManager.GetCurrentBrandingElement(BrandingElementType.AKJ_Sharepoint_Css);

            // Should master be rebranded?
            if (master != null && master.Element != "")
            {
                RebrandMaster(page, master);
            }

            // Should css be rebranded?
            if (css != null && css.Element != "")
            {
                HttpResponse reponse = HttpContext.Current.Response;

                if (reponse != null)
                {
                    //Delegate CSS rebranding to response filter
                    CSSInjectFilter filter = new CSSInjectFilter(reponse.Filter);
                    filter.CssPath = css.Element;
                    reponse.Filter = filter;
                }                
            }
        }
        
        /// <summary>
        /// Rebrand the Master Page.
        /// </summary>
        /// <param name="page"></param>
        /// <param name="applyMasterElement"></param>
        private void RebrandMaster(Page page, BrandingPair applyMasterElement)
        {
            // If the request originates from a Publishing Page then we have to
            // change the master page on the current Sharepoint Web instance object
            // (of course we don't want to persist this change since it would
            // change the master page permanently..for all users).
            if (page is PublishingLayoutPage || page is TemplateRedirectionPage)
            {  
                //web.Site.AllowUnsafeUpdates = true;
                SPContext.Current.Web.CustomMasterUrl = applyMasterElement.Element;
            }
            else
            {
                // Now, if this is a normal wss 3.0 page hook into
                // the PreInit event (just before the ordinary Page event
                // cycle starts.                                
                page.MasterPageFile = applyMasterElement.Element;
            }
        }
        
        /// <summary>
        /// Load and return interceptors modules
        /// </summary>
        /// <returns></returns>
        private SortedDictionary<int, IBrandingInterceptor> GetBrandingInterceptors()
        {
            VisualBrandingSection config = VisualBrandingSection.Instance();

            SortedDictionary<int, IBrandingInterceptor> interceptors = new SortedDictionary<int, IBrandingInterceptor>();

            // Fetch and Unwrap Interceptors
            // TODO: Perform some caching of already loaded insectors to reduce reflection/instantiation.
            foreach (BrandingInterceptorElement interceptor in config.BrandingInterceptors)
            {
                IBrandingInterceptor i = AppDomain.CurrentDomain.CreateInstanceAndUnwrap(interceptor.Assembly, interceptor.Type) as IBrandingInterceptor;

                if (i != null)
                    interceptors.Add(int.Parse(interceptor.Priority), i);
            }

            return interceptors;
        }
    }    
}